const PENDIND = 'pending',
      FULFILLED = 'fulfilled',
      REJECTED = 'rejected';

function parse(newPromise, result, resolve, reject) {
  if (newPromise === result) {
    return reject(new TypeError('Chaining cycle detected for MyPromise'));
  }
  try {
    if (result instanceof MyPromise) {
      result.then(resolve, reject)
    } else {
      resolve(result);
    }
  } catch (error) {
    reject(error);
  }
  
}


class MyPromise {
  constructor (executor) {
    this.state = PENDIND;
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state === PENDIND) {
        this.state = FULFILLED;
        this.value = value;
        // 等待完成时再进行调用
        // 发布
        this.onResolvedCallbacks.forEach(fn => fn());
      }
    }

    const reject = (reason) => {
      if (this.state === PENDIND) {
        this.state = REJECTED;
        this.reason = reason;
        // 发布
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    }
    try {
      // 将外部逻辑的值设置到内部，给then或者catch
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  // 成功的条件
  // then return 普通的JavaScript value
  // then return 新的promise成功态的结果value
  // 失败的条件
  // then return新的promise失败态的原因reason
  // then 抛出了异常
  // promise 链式调用
  // then 不具备this
  // return new Promise
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
    let newPromise = new MyPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        setTimeout(() => {
          parse(newPromise, onFulfilled(this.value), resolve, reject);
        }, 0);
      }
      if (this.state === REJECTED) {
        setTimeout(() => {
          parse(newPromise, onRejected(this.reason), resolve, reject);
        }, 0);
      }
       // 如果还是在等待就存储起来
      if (this.state === PENDIND) {
        // 订阅
        this.onResolvedCallbacks.push(() => {
          parse(newPromise, onFulfilled(this.value), resolve, reject)
        });
        this.onRejectedCallbacks.push(() => {
          parse(newPromise, onRejected(this.reason), resolve, reject)
        });
      }
    });
    return newPromise;
  }

  catch(errorCallback) {
    return this.then(null, errorCallback);
  }

  static resolve(value) {
    return new MyPromise((resolve, reject) => {
      if (value instanceof MyPromise) {
        value.then(resolve, reject);
      } else {
        resolve(value);
      }
    });
  }

  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    });
  }
}
module.exports = MyPromise;